<?php
    if (!defined('__IS_LEAF__')) exit('Access Denied!');
    
    /**
     * 路由器类，负责解析当前url，返回应该运行的app或group信息
     * 告知app类运行的app信息，然后app去执行
     * 主要对开开放两个方法：第一个初始（应用或分组，通过传参的方式）化方法，第二个是获取入口方法
     */

    class Router {

        static private $runType;        //运行模式：app、group
        static private $appBoot;        //当前正在运行的app的入口文件
        static private $currentUrl;     //当前页面的完整url
        static private $params;         //当前的query参数
        //默认App参数
        static private $defaultAppParams = array();


        /**
         * 初始化路由器
         * @access public
         */
        static public function routeInit($type){
            !defined('__URL__') && define('__URL__', 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
            //定义常量，防止重复的调用的函数读取配置，影响效率
            define('__M__', C('url_controler_name'));
            define('__A__', C('url_action_name'));
            self::$defaultAppParams = array(
                                                __M__=>'index',    //默认控制器
                                                __A__=>'index'    //默认行为
                                            );
            self::$currentUrl = __URL__;
            //获取运行类型：app或group
            self::$runType = $type;
            //整合参数
            self::setParams();
            //运行分组或应用，并返回对应的要被调用信息
            $runInfo = 'get'.ucfirst(self::$runType).'Info';
            //返回appRunInfo或groupRunInfo，$runInfo为runAppInfo或runGroupInfo
            return self::$runInfo();
        }

        /**
         * 获取当前应用的入口文件
         */
        static public function getBoot(){
            /*
                获取当前入口文件，必须根据普通模式或pathinfo模式处理，因为pathinfo模式，无法使用parse_url获取query信息，只有这样才能正确获取入口文件，该处理很重要
            */
            !defined('__URL__') && define('__URL__', 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
            $currentUrl = __URL__;
            switch (C('url_mode')) {
                case '1':
                    $urlInfo = parse_url($currentUrl);
                    break;
                case '2':
                    //$urlInfo = parse
                    $urlInfo = parse_url( str_replace($_SERVER['PATH_INFO'], '', $currentUrl) );
                    break;
                default:
                    break;
            }
            $boot = trim( strrchr($urlInfo['path'], '/'), '/');
            //如果无法通过url获取入口，则入口为默认的index.php
            empty($boot) && $boot='index.php';
            self::$appBoot = $boot;
            return $boot;
        }

        /**
         * 设置参数列表数组，主要包含m和a，以及其他一些参数和值
         * @access private
         */
        static private function setParams(){
            //获取当前url
            switch (C('url_mode')) {
                //如果url模式为普通模式
                case '1':
                    $queryNew = self::parseNormalUrl(); 
                    break;
                //如果为自定义模式（也就是pathinfo模式），注意：该模式因为无法获取$_GET的值，所以框架会处理
                //此模式支持普通模式和pathinfo模式参数混写，如果index.php/Index/index/&aa=sss&kk=lll，不过只能写在最后
                default:
                    //如果开发者在pathinfo模式下使用的普通url，主要是判断$_SERVER['PATH_INFO']是否有pathinfo模式的内容以做对应的处理
                    $queryNew = $_SERVER['PATH_INFO'] ? self::parsePathinfoUrl() : self::parseNormalUrl();
                    break;
            }
            //去除get参数中的m和a
            unset($_GET[__M__]);
            unset($_GET[__A__]);
            //合并用户参数和默认参数
            $params['params'] = array_merge(self::$defaultAppParams, $queryNew);
            self::$params = $params;
        }

        /**
         * 解析普通url参数为参数数组列表
         */
        static private function parseNormalUrl(){
            //解析url
            $params = parse_url(self::$currentUrl);
            //以&分隔符分割query部分
            $query = explode('&', $params['query']);
            //将query部分的字符串转为数组，成为query参数数组
            $queryNew = array();
            foreach ($query as $key => $value) {
                $valueArr = explode('=', $value);
                if(count($valueArr)>1){
                    $queryNew[$valueArr[0]] = $valueArr[1];
                }
            }
            return $queryNew;
        }

        /**
         * 解析pathinfo模式的url为参数数组列表，此模式兼容普通url模式
         */
        static private function parsePathinfoUrl(){
            //解析url
            $params = parse_url(self::$currentUrl);
            //获取pathinfo部分的字符串，pathinfo模式的根本
            $pathinfo = trim($_SERVER['PATH_INFO'], '/');
            //处理url，使得可以支持pathinfo和普通url混写。主要是字符串替换，将正常部分转化为pathinfo模式，然后再拼装
            $queryEx = strstr($pathinfo, '&');
            $pathinfo = trim(str_replace($queryEx, '', $pathinfo), '/');
            $queryEx = '/'.str_replace(array('=','&'), '/', $queryEx);
            $pathinfo = $pathinfo.$queryEx;
            //用自定义分隔符分割，默认用/
            $pathinfoArr = explode(C('url_define_sp'), $pathinfo);
            $queryNew = array();
            //两两分割参数数组，然后遍历，来使得参数和值对应
            $paramsArr = array_chunk($pathinfoArr, 2);
            foreach ($paramsArr as $key => $value) {
                if($key==0){
                    !empty($value[0]) && $queryNew[__M__] = $value[0];
                    !empty($value[1]) && $queryNew[__A__] = $value[1];
                }else{
                    $queryNew[$value[0]] = $value[1];
                }
            }
            //设置$_GET，以便可以使$_GET获取pathinfo模式的参数
            $_GET = $queryNew;
            self::gpcSet();
            return $queryNew;
        }

        /**
         * 魔术引用的处理和处理gpc的特殊字符
         */
        static private function gpcSet(){
            //设置对魔术引用的处理和处理gpc的特殊字符
            if (!get_magic_quotes_gpc()) {
                $gpc = array(&$_POST,&$_GET,&$_COOKIE,&$_REQUEST);
                foreach ($gpc as $gpcKey=>&$value) {
                    if( !empty($value) ){
                        $value = array_map('addslashes', $value);
                    }
                }
            }
        }

        /**
         * 经过路由器解析后app运行信息
         * @access private
         * @return array $appRunInfo 返回要调用的action和数组信息
         */
        static private function getAppInfo(){
            //获取当前正在运行的入口文件
            self::getBoot();
            $params = self::$params;
            $appRunInfo = array();
            $appRunInfo['controller'] = $params['params'][__M__];
            $appRunInfo['action'] = $params['params'][__A__];
            //下起三行代码获取当前app名称
            $appInfo = GL('app');
            //获取当前应用的名称
            $appRunInfo['app'] = $appInfo['name'];
            //返回当前app信息
            return $appRunInfo;
        }

        static private function groupRunInfo(){
        }


    }